﻿using System;
using System.Data;
using System.Configuration;

using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections;
using TA.JSON;
using System.Collections.Generic;
using System.ComponentModel;

namespace TA.Turbo.Controls
{
	/// <summary>
	/// List item in a list control.
	/// </summary>
	public class ListItem : IJsonSerializable, IJsonDeserializable // : BaseListItem
	{
		#region PUBLIC
		#region INIT
		/// <summary>
		/// Ctor.
		/// </summary>
		public ListItem()
		{
			Visible = true;
			Enabled = true;
			//Selected
			_items = new ListItemCollection { _owner = this };
		}
		/// <summary>
		/// Copy ctor.
		/// </summary>
		/// <param name="li"></param>
		public ListItem(ListItem li)
		{
			this.CssClass = li.CssClass;
			this.Enabled = li.Enabled;
			this.Text = li.Text;
			this.Value = li.Value;
			this.Visible = li.Visible;
			foreach (string key in li.Attributes.Keys)
				this.Attributes[key] = li.Attributes[key];
			//Selected
			_items = new ListItemCollection { _owner = this };
			this._items.AddRange(li.Items);
		}
		#endregion
		#region PROPS
		/// <summary>
		/// The value that the list control returns when this item is selected. If empty, defaults to <see cref="Text"/>.
		/// </summary>
		[DefaultValue("")]
		[Category("Behavior")]
		public string Value
		{
			get
			{
				if (this._value == null)
					return this._text;
				return this._value;
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");
				if (this._value != null && this.Owner != null && this.Owner.Items._itemsByValue.ContainsKey(this._value))
					this.Owner.Items._itemsByValue.Remove(this._value);

				this._value = value;

				if (this.Owner != null)
					this.Owner.Items._itemsByValue[this._value] = this;
			}
		}
		/// <summary>
		/// Attributes that will be applied to this list item.
		/// </summary>
		[Category("Behavior")]
		public System.Web.UI.AttributeCollection Attributes { get { return _attributes; } }
		/// <summary>
		/// Styles that will be applied to this list item.
		/// </summary>
		[Category("Appearance")]
		public CssStyleCollection Style { get { return _attributes.CssStyle; } }
		/// <summary>
		/// CSS class that will be applied to this list item.
		/// </summary>
		[Category("Appearance")]
		public string CssClass { get; set; }
		/// <summary>
		/// The text to be displayed in this item.
		/// </summary>
		[DefaultValue("")]
		[Category("Behavior")]
		public string Text
		{
			get
			{
				if (this._text == null)
					return this._value;
				return this._text;
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");
				if (this._text != null && this.Owner != null && this.Owner.Items._itemsByText.ContainsKey(this._text))
					this.Owner.Items._itemsByText.Remove(this._text);

				this._text = value;

				if (this.Owner != null)
					this.Owner.Items._itemsByText[this._text] = this;
			}
		}
		/// <summary>
		/// Specifies whether this list item is visible or not.
		/// </summary>
		[Category("Behavior")]
		[DefaultValue(true)]
		public bool Visible { get; set; }
		/// <summary>
		/// Specifies whether this list item is enabled. If it's disabled, it can't be selected.
		/// </summary>
		[Category("Behavior")]
		[DefaultValue(true)]
		public bool Enabled { get; set; }
		/// <summary>
		/// Returns the <see cref="Text"/> of this item.
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return Text;
		}
		/// <summary>
		/// Gets the collection of sub-items.
		/// </summary>
		[PersistenceMode(PersistenceMode.InnerProperty)]
		public ListItemCollection Items { get { return _items; } }
		#endregion
		#region METHODS
		/// <summary>
		/// Adds the "class" and "disable" attributes and display style attribute (for Visible property).
		/// </summary>
		/// <param name="writer"></param>
		public void AddAttributes(HtmlTextWriter writer)
		{
			if (!string.IsNullOrEmpty(this.CssClass))
				writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass);
			if (!this.Visible)
				writer.AddStyleAttribute(HtmlTextWriterStyle.Display, "none");
			if (!this.Enabled)
				writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled");
			this.Attributes.AddAttributes(writer);
		}
		#endregion
		#endregion
		#region INTERNAL
		#region VARS
		string _value, _text;
		internal ListItemCollection _owner;
		System.Web.UI.AttributeCollection _attributes = new System.Web.UI.AttributeCollection(new StateBag(true));
		ListItemCollection _items;
		#endregion
		#region PROPS
		internal BaseListControl Owner
		{
			get
			{
				if (_owner == null) return null;
				return _owner.Owner;
			}
		}
		internal bool Selected { get; set; }
		#endregion
		#region METHODS
		#region IJsonSerializable Members
		/// <summary>
		/// IsDirty.
		/// </summary>
		bool IJsonSerializable.IsDirty
		{
			get
			{
				return
					!this.Enabled
					|| !this.Visible
					|| this.Items.Count > 0
					|| !string.IsNullOrEmpty(this.Text)
					|| !string.IsNullOrEmpty(this.Value)
					|| this.Style.Count > 0
					|| this.Attributes.Count > 0
					|| !string.IsNullOrEmpty(this.CssClass);
			}
		}
		/// <summary>
		/// Serialize.
		/// </summary>
		/// <param name="jw"></param>
		void IJsonSerializable.Serialize(JsonWriter jw)
		{
			this.SerializeObject(jw);
		}
		/// <summary>
		/// SerializeContents.
		/// </summary>
		/// <param name="jw"></param>
		void IJsonSerializable.SerializeContents(JsonWriter jw)
		{
			if (!this.Enabled)
			{
				jw.PropertyName("E");
				jw.Value(this.Enabled);
			}

			if (!this.Visible)
			{
				jw.PropertyName("L");
				jw.Value(this.Visible);
			}

			if (this.Items.Count > 0)
			{
				jw.PropertyName("I");
				jw.StartArray();
				foreach (ListItem li in this.Items)
					((IJsonSerializable)li).Serialize(jw);
				jw.EndArray();
			}

			if (!string.IsNullOrEmpty(this.Text))
			{
				jw.PropertyName("T");
				jw.Value(this.Text);
			}

			if (!string.IsNullOrEmpty(this.Value))
			{
				jw.PropertyName("V");
				jw.Value(this.Value);
			}

			if (!string.IsNullOrEmpty(this.CssClass))
			{
				jw.PropertyName("C");
				jw.Value(this.CssClass);
			}

			if (this.Style.Count > 0)
			{
				jw.PropertyName("S");
				jw.Value(this.Style.Value);
			}

			if (this.Attributes.Count > 0)
			{
				jw.PropertyName("A");
				jw.StartObject();
				foreach (string key in this.Attributes.Keys)
				{
					jw.PropertyName(key);
					jw.Value(this.Attributes[key]);
				}
				jw.EndObject();
			}
		}
		#endregion

		#region IJsonDeserializable Members
		/// <summary>
		/// Deserialize.
		/// </summary>
		/// <param name="jr"></param>
		void IJsonDeserializable.Deserialize(IJsonReader jr)
		{
			this.DeserializeObject(jr);
		}
		/// <summary>
		/// DeserializeContent.
		/// </summary>
		/// <param name="jr"></param>
		/// <param name="propShortName"></param>
		void IJsonDeserializable.DeserializeContent(IJsonReader jr, string propShortName)
		{
			switch (propShortName)
			{
				case "E":
					this.Enabled = (bool)jr.Value; break;
				case "L":
					this.Visible = (bool)jr.Value; break;
				case "I":
					if (jr.TokenType != JsonToken.StartArray) throw new Exception();
					jr.Read();
					this.Items.Clear();
					while (jr.TokenType != JsonToken.EndArray)
					{
						ListItem li = new ListItem();
						((IJsonDeserializable)li).Deserialize(jr);
						this.Items.Add(li);

						jr.Read();
					}
					break;
				case "T":
					this.Text = (string)jr.Value; break;
				case "V":
					this.Value = (string)jr.Value; break;
				case "C":
					this.CssClass = (string)jr.Value; break;
				case "S":
					this.Style.Value = (string)jr.Value; break;
				case "A":
					if (jr.TokenType != JsonToken.StartObject) throw new Exception();
					jr.Read();
					this.Attributes.Clear();
					while (jr.TokenType != JsonToken.EndObject)
					{
						string name = (string)jr.Value;
						jr.Read();
						string value = (string)jr.Value;
						jr.Read();

						this.Attributes[name] = value;
					}
					break;
			}
		}

		#endregion
		#endregion
		#endregion

	}
}